/*
 * Interface del servicio de subscripción a un contexto
 */

package ocp.service.impl;

import java.util.Vector;
import ocp.service.ContextConsumer;
import ocp.service.ContextProducer;
import ocp.service.ContextService;
import ocp.context.Context;
import ocp.util.Log;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;


/**
 *
 * @author Paco Lopez Marmol
 */
public class ContextServiceImpl implements ContextService  {
    
    ContextManagement cm;
    private BundleContext bc;
    
    
    /**
     * constructor
     * @param bc BundleContext
     * @param cm ContextManagement 
     */
    public ContextServiceImpl(BundleContext bc,ContextManagement cm) {
        this.cm = cm;
        this.bc = bc;
    }
    
    /**
     * Activa el listener de consumidores y productores
     */
    void open() {
        
        ServiceListener sl = new ServiceListener() {
            public void serviceChanged(ServiceEvent ev) {
                ServiceReference sr = ev.getServiceReference();
                //String id = (String)sr.getProperty("id");
                Object servicio = bc.getService(sr);
                
                // Gestion de ContexProducers --------------------------
                if( servicio instanceof ContextProducer )  {
                    ContextProducer cp = (ContextProducer)servicio;
                    switch (ev.getType()) 
                    {
                    case ServiceEvent.REGISTERED: 
                        try {
                            producerAdd(cp);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    case ServiceEvent.UNREGISTERING: 
                        try {
                            producerDel(cp);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                }
                // Gestion de ContexConsumers --------------------------
                else if( servicio instanceof ContextConsumer )  {
                    ContextConsumer cs = (ContextConsumer)servicio;
                    switch (ev.getType()) 
                    {
                    case ServiceEvent.REGISTERED: 
                        try {
                            consumerAdd(cs);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    case ServiceEvent.UNREGISTERING: 
                        try {
                            consumerDel(cs);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        break;
                    }
                }
                    
            }

        };

        // filtro que selecciona los servicios que vamos a escuchar
        String filter = "(|(objectclass=" + ContextProducer.class.getName() + ")" +
                        "(objectclass=" + ContextConsumer.class.getName() + "))"
                                ;
        try {
            bc.addServiceListener(sl, filter);
            
            // Crea los servicios actualmente registrados
            ServiceReference[] srl = bc.getServiceReferences(null, filter);
            for (int i = 0; srl != null && i < srl.length; i++) {
                Object servicio = bc.getService(srl[i]);
                if( servicio instanceof ContextProducer )
                    producerAdd( (ContextProducer)servicio );
                else if( servicio instanceof ContextConsumer )
                    consumerAdd( (ContextConsumer)servicio );
                srl[i] = null;
            }
            srl = null;
        } catch (InvalidSyntaxException e) {
            e.printStackTrace();
        }
        
    }

    private void consumerAdd(ContextConsumer cs)  {
        Log.logInfo( "OCP: Add ContextConsumer id: " + cs.getId() ); 
        if( cm.consumerAdd(cs) )
            cs.activate(this);
    }
    
    private void consumerDel(ContextConsumer cs) {
        Log.logInfo( "OCP: Remove ContextConsumer id: " + cs.getId() );
        cm.consumerDel(cs);
    }
    
    private void producerAdd(ContextProducer cp)  {
        Log.logInfo( "OCP: Add ContextProducer id: " + cp.getId() );
        if( cm.producerAdd(cp) )
            cp.activate(this);
    }
    
    private void producerDel(ContextProducer cp) {
        cm.producerDel(cp);
        Log.logInfo( "OCP: Remove ContextProducer id: " + cp.getId() );
    }
    
    /***************************************************************************
     *  ContextService Methods Implementation
     **************************************************************************/
    
    
    public boolean register(String id,ContextConsumer cl)
    {
        cm.register( id , cl );
        
        return true;
    }
    
    public void registerToContextType(String type, ContextConsumer cl) 
    {
        cm.registerToContextType(type, cl);
    }
     
    public boolean unregister(String id,ContextConsumer cl)
    {
        cm.unregister( id , cl );
        
        return true;
    }

    public Context read(String id) {
        return cm.read( id );
    }

    public void write(Context context) {
        cm.write( context );
    }
    
    /**
     * Obtiene el número de contextos almacenados en el historico de un 
     * contexto concreto.
     * @param id Identificador del contexto
     * @return Número de contextos almacenados
     */
    public int getHistoricalContextLenght(String id)  {
        return cm.getHistoricalContextLenght(id);
    }
    
    /** 
     * Lee los últimos valores del historico de un contexto
     * @param id Identificador del contexto
     * @param nitems Número de contextos a leer
     * @return Un vector de contextos ordenado de menos reciente a más reciente
     */
    public Vector<Context> readHistoricalContextLast(String id,int nitems)  {
        return cm.readHistoricalContextLast(id,nitems);
    }
    
}
